// UUID_NIL 常量定义
const UUID_NIL = '00000000-0000-0000-0000-000000000000'

// 更新指定ID的节点
export function updateTreeNodeById(tree, targetId, updateCallback) {
    // 防御性检查：确保tree是数组
    const safeTree = Array.isArray(tree) ? tree : []
    const newTree = JSON.parse(JSON.stringify(safeTree))

    // 若 targetId 为空/未提供，则视为对根级数据进行更新
    if (targetId === undefined || targetId === null || targetId === '') {
        const virtualRoot = { id: null, children: newTree }
        updateCallback(virtualRoot)
        return virtualRoot.children || newTree
    }

    function findAndUpdate(node) {
        // 确保节点存在
        if (!node) return false

        // 兼容字符串/数字类型不一致的情况
        if (String(node.id) === String(targetId)) {
            updateCallback(node)
            return true
        }

        // 安全检查children是否存在且为数组
        if (Array.isArray(node.children) && node.children.length > 0) {
            for (let i = 0; i < node.children.length; i++) {
                if (findAndUpdate(node.children[i])) {
                    return true
                }
            }
        }

        return false
    }

    // 遍历根节点
    for (let i = 0; i < newTree.length; i++) {
        if (findAndUpdate(newTree[i])) {
            return newTree
        }
    }

    return newTree
}

export function buildChatItemTree(allMessages) {
    const map = {}
    const rootNodes = []
    const childrenCount = {}

    let lastAppendedLegacyAnswer = null
    for (let i = 0; i < allMessages.length; i += 2) {
        const question = allMessages[i]
        const answer = allMessages[i + 1]

        const isLegacy = question.parentMessageId === UUID_NIL
        const parentMessageId = isLegacy
            ? (lastAppendedLegacyAnswer?.id || '')
            : (question.parentMessageId || '')

        childrenCount[parentMessageId] = (childrenCount[parentMessageId] || 0) + 1
        const questionNode = {
            ...question,
            children: [],
        }
        map[question.id] = questionNode

        childrenCount[question.id] = 1
        const answerNode = {
            ...answer,
            children: [],
            siblingIndex: isLegacy ? 0 : childrenCount[parentMessageId] - 1,
        }
        map[answer.id] = answerNode

        questionNode.children.push(answerNode)

        if (isLegacy) {
            if (!lastAppendedLegacyAnswer) {
                rootNodes.push(questionNode)
            } else {
                lastAppendedLegacyAnswer.children.push(questionNode)
            }

            lastAppendedLegacyAnswer = answerNode
        } else {
            if (
                !parentMessageId
                || !allMessages.some(item => item.id === parentMessageId)
            ) {
                rootNodes.push(questionNode)
            } else {
                if (map[parentMessageId] && map[parentMessageId].children) {
                    map[parentMessageId].children.push(questionNode)
                }
            }
        }
    }

    return rootNodes
}

export function getThreadMessages(tree, targetMessageId) {
    let ret = []
    let targetNode

    const stack = tree.slice().reverse().map(rootNode => ({
        node: rootNode,
        path: [rootNode],
    }))
    while (stack.length > 0) {
        const { node, path } = stack.pop()
        if (
            node.id === targetMessageId
            || (!targetMessageId && !node.children?.length && !stack.length)
        ) {
            targetNode = node
            ret = path.map((item, index) => {
                if (!item.isAnswer)
                    return item

                const parentAnswer = path[index - 2]
                const siblingCount = !parentAnswer ? tree.length : parentAnswer.children?.length
                const prevSibling = !parentAnswer ? tree[item.siblingIndex - 1]?.children?.[0]?.id : parentAnswer.children?.[item.siblingIndex - 1]?.children?.[0]?.id
                const nextSibling = !parentAnswer ? tree[item.siblingIndex + 1]?.children?.[0]?.id : parentAnswer.children?.[item.siblingIndex + 1]?.children?.[0]?.id
                return { ...item, siblingCount, prevSibling, nextSibling }
            })
            break
        }
        if (node.children) {
            for (let i = node.children.length - 1; i >= 0; i--) {
                stack.push({
                    node: node.children[i],
                    path: [...path, node.children[i]],
                })
            }
        }
    }

    if (targetNode) {
        const stack = [targetNode]
        while (stack.length > 0) {
            const node = stack.pop()
            if (node !== targetNode)
                ret.push(node)
            if (node.children?.length) {
                const lastChild = node.children.at(-1)

                if (!lastChild.isAnswer) {
                    stack.push(lastChild)
                    continue
                }
                const parentAnswer = ret.at(-2)
                const siblingCount = parentAnswer?.children?.length
                const prevSibling = parentAnswer?.children?.at(-2)?.children?.[0]?.id
                stack.push({ ...lastChild, siblingCount, prevSibling })
            }
        }
    }

    return ret
}

export function getFormattedChatList(messages) {
    const newChatList = []
    messages.forEach((item) => {
        const questionFiles = item.message_files?.filter((file) => file.belongs_to === 'user') || []
        newChatList.push({
            id: `question-${item.id}`,
            content: item.query,
            isAnswer: false,
            //   message_files: getProcessedFilesFromResponse(questionFiles.map((item) => ({ ...item, related_id: item.id }))),
            parentMessageId: item.parent_message_id || undefined,
            parent_message_id: item.parent_message_id || undefined,
            query: item.query,
        })
        const answerFiles = item.message_files?.filter((file) => file.belongs_to === 'assistant') || []
        newChatList.push({
            id: item.id,
            content: item.answer,
            //   agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
            feedback: item.feedback,
            isAnswer: true,
            citation: item.retriever_resources,
            //   message_files: getProcessedFilesFromResponse(answerFiles.map((item) => ({ ...item, related_id: item.id }))),
            parentMessageId: `question-${item.id}`,
            parent_message_id: item.parent_message_id || undefined,
            query: item.query,
        })
    })
    return newChatList
}

export function isValidGeneratedAnswer(item) {
    return !!item && item.isAnswer && !item.id.startsWith('answer-placeholder-') && !item.isOpeningStatement
}

export function getLastAnswer(chatList) {
    for (let i = chatList.length - 1; i >= 0; i--) {
        const item = chatList[i]
        if (isValidGeneratedAnswer(item))
            return item
    }
    return null
}

